//
// Created by sanfen on 2021/3/9.
//

#include "Monitor64x32.h"

void Monitor64x32::link_cpu(CHIP8 &chip8) {
    this->cpu=chip8;
}

Monitor64x32::Monitor64x32(QWidget *parent) :QMainWindow(parent){
    QTimer *timer=new QTimer(this);     //定时器
    timer->start(10);

    glwindow=new Monitor64x32GL(this);//设置绘制界面
    setCentralWidget(glwindow);//设置OpenGL界面到主窗体
    glwindow->setMinimumSize(640,320);
    this->setMaximumSize(640,320);

    connect(timer,SIGNAL(timeout()),this,SLOT(timeout_sc()));
    connect(glwindow,SIGNAL(paintGL()),this,SLOT(paint_screen()));
    connect(this,SIGNAL(repaint_screen()),glwindow,SLOT(repaint()));
    //链接绘制函数和OpenGL界面的绘制函数
    connect(this,SIGNAL(draw_pixel(int, int, float)),glwindow,SLOT(paint_pixel(int, int, float)));

}

//绘制像素
void Monitor64x32::paint_cell(int row, int col, unsigned char color) {
    int pixel_row=row*PIXEL_SIZE;
    int pixel_col=col*PIXEL_SIZE;
    int drow,dcol;

    for (drow=0;drow<PIXEL_SIZE;drow++){
        for(dcol=0;dcol<PIXEL_SIZE;dcol++){
            paint_pixel(pixel_row+drow,pixel_col+dcol,color);
        }
    }
}

//绘制像素到屏幕
void Monitor64x32::paint_pixel(int row, int col, unsigned char color) {
    row=cpu.screen_rows-1-row;
    cpu.screen[row][col][0]=cpu.screen[row][col][1]=cpu.screen[row][col][2]=color;
}

//绘图函数
void Monitor64x32::paint_screen() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    for(int row=0;row<GFX_ROWS;row++){
        for(int col=0;col<GFX_COLS;col++){
            paint_cell(row,col,cpu.gfx[row][col]?WHITE:BLACK);
        }
    }
    glDrawPixels(SCREEN_COLS,SCREEN_ROWS,GL_RGB,GL_UNSIGNED_BYTE,(void *) cpu.screen);
    glPixelZoom(2,2);
}

//按键按下事件
void Monitor64x32::keyPressEvent(QKeyEvent *event) {
    unsigned char k=event->key();
    int index=keymap(k);
    if(index>=0) cpu.setkeys(index,1);
}

int Monitor64x32::keymap(unsigned char k) {
    switch(k){
        case '1':
            return 0x1;
        case '2':
            return 0x2;
        case '3':
            return 0x3;
        case '4':
            return 0xc;
        case 'Q':
            return 0x4;
        case 'W':
            return 0x5;
        case 'E':
            return 0x6;
        case 'R':
            return 0xd;
        case 'A':
            return 0x7;
        case 'S':
            return 0x8;
        case 'D':
            return 0x9;
        case 'F':
            return 0xe;
        case 'Z':
            return 0xa;
        case 'X':
            return 0x0;
        case 'C':
            return 0xb;
        case 'V':
            return 0xf;
        default:
            return -1;
    }
}

//按键释放事件
void Monitor64x32::keyReleaseEvent(QKeyEvent *event) {
    unsigned char k=event->key();

    int index=keymap(k);
    if(index>=0) cpu.setkeys(index,0);
}

Monitor64x32::~Monitor64x32()  {
    delete glwindow;
}

//定时器事件
void Monitor64x32::timeout_sc() {
    struct timeval clock_now;
    gettimeofday(&clock_now,NULL);
    cpu.runCycle();

    if(cpu.draw_flag){
        repaint_screen();
        cpu.draw_flag= false;
    }
    if(timediff_ms(&clock_now,&clock_prev)>=cpu.clock_rate_ms){
        cpu.tick();
        clock_prev=clock_now;
    }
}

//分频器
int Monitor64x32::timediff_ms(struct timeval *end, struct timeval *start) {
    int diff=(end->tv_sec-start->tv_sec)*1000+(end->tv_usec-start->tv_usec)/1000;
    //printf("timediff=%d\n",diff);
    return diff;
}